"""
输入：标注数据
输出：每个动作以及它的参数和关系
"""
class MyLocation:
    def __init__(self, id_loc, name, direction=None) -> None:
        self.id = id_loc
        self.name = name
        self.direction = direction

class MyBackground:
    def __init__(self, name, loc: MyLocation=None) -> None:
        self.name = name
        self.loc = loc

class MyAction:
    def __init__(self, my_type, trigger, subject=None, object=None, indirect_object=None, background=None, location=None, constraint=None, direction=None, original_name=None, another_name=None, x_occurs=None) -> None:
        self.my_type = my_type
        self.trigger = trigger
        self.subject = subject
        self.object = object
        self.indirect_object = indirect_object
        self.background = background
        self.location = location
        self.constraint = constraint
        self.direction = direction
        self.original_name = original_name
        self.another_name = another_name
        self.x_occurs = x_occurs

import os
import json

cur_path = os.path.abspath(os.path.dirname(__file__))

# 从 json 文件中读数据
def read_from_json(filename):
    try:
        with open(os.path.join(cur_path, filename), 'r', encoding='utf-8') as f:
            data = json.load(f)
        return data
    except Exception as e:
        print("读取文件出错：", e)

def read_from_file(filename):
    try:
        with open(os.path.join(cur_path, filename), 'r', encoding='utf-8') as f:
            data = f.readlines()
        return data
    except Exception as e:
        print("读取文件出错：", e)

def add_to_file(filename, data):
    try:
        with open(os.path.join(cur_path, filename), 'a+', encoding='utf-8') as f:
            f.write(data)
    except Exception as e:
        print("写入文件出错：", e)

def clear_file(filename):
    try:
        with open(os.path.join(cur_path, filename), 'w', encoding='utf-8') as f:
            f.write('')
    except Exception as e:
        print("清空文件出错：", e)

def validate_little_red_hat(label_data, story, action_label):
    for data_ele in label_data:
        # 如果 data_ele["data"]["text"] 包含字符串 "小红帽"
        if "小红帽" in data_ele["data"]["text"]:
            result_little_red_hat = data_ele["annotations"][0]["result"]
    
    # 关键动作列表
    key_action_list = []

    # 遍历 result_little_red_hat 列表，封装动作 n 元组
    for result_ele in result_little_red_hat:
        # 如果 result_ele 有 "value" 键，并且 "value" 键有 "labels" 键，并且 label 是动作标签
        if "value" in result_ele and "labels" in result_ele["value"] and result_ele["value"]["labels"][0] in action_label:

            # 创建 MyAction 对象
            my_action = MyAction(result_ele["value"]["labels"][0], story[0][result_ele["value"]["start"]:result_ele["value"]["end"]])

            # temp: 存背景对象
            temp_backgrounds = []

            # 查找参数
            id_action = result_ele["id"]
            for result_ele_rel in result_little_red_hat:
                if result_ele_rel["type"] == "relation":
                    if result_ele_rel["to_id"] == id_action:
                        txt_rel = result_ele_rel["labels"][0]
                        from_id = result_ele_rel["from_id"]
                        for result_ele_ent in result_little_red_hat:
                            if result_ele_ent["type"] == "labels" and result_ele_ent["id"] == from_id:
                                txt_arg = story[0][result_ele_ent["value"]["start"]:result_ele_ent["value"]["end"]]

                                # 为 my_action 添加参数
                                if txt_rel == "act:subject-of":
                                    my_action.subject = txt_arg
                                elif txt_rel == "act:object-of":
                                    my_action.object = txt_arg
                                elif txt_rel == "act:indirect-object-of":
                                    my_action.indirect_object = txt_arg
                                elif txt_rel == "act:bkg-of":
                                    # 为了封装一个 Background 对象
                                    temp_backgrounds.append({from_id: txt_arg})
                                elif txt_rel == "act:constraint-of":
                                    my_action.constraint = txt_arg
                                elif txt_rel == "act:original-name-of":
                                    my_action.original_name = txt_arg
                                elif txt_rel == "act:another-name-of":
                                    my_action.another_name = txt_arg
                                # elif txt_rel == "act:direction-of":
                                #     my_action.direction = txt_arg
                                # elif txt_rel == "act:loc-of":
                                #     my_action.location.append(txt_arg)
                                
                                break

            # 封装背景对象的背景名和地点名，bkg.name 和 bkg.loc
            action_bkgs = []
            for temp_background in temp_backgrounds:
                my_bkg = MyBackground(list(temp_background.values())[0])
                id_bkg = list(temp_background.keys())[0]
                flag = False
                for result_ele_bkg_rel in result_little_red_hat:
                    if result_ele_bkg_rel["type"] == "relation" and result_ele_bkg_rel["to_id"] == id_bkg:
                        txt_bkg_rel = result_ele_bkg_rel["labels"][0]
                        if txt_bkg_rel == "act:loc-of":
                            id_loc = result_ele_bkg_rel["from_id"]
                            for result_ele_loc in result_little_red_hat:
                                if result_ele_loc["type"] == "labels" and result_ele_loc["id"] == id_loc:
                                    my_bkg.loc = MyLocation(id_loc, story[0][result_ele_loc["value"]["start"]:result_ele_loc["value"]["end"]])
                                    flag = True
                                    break
                        if flag:
                            break
                action_bkgs.append(my_bkg)

            # 封装背景对象的方位，bkg.loc.direction
            for action_bkg in action_bkgs:
                if action_bkg.loc is not None:
                    id_loc = action_bkg.loc.id
                    for loc_rel in result_little_red_hat:
                        if loc_rel["type"] == "relation" and loc_rel["to_id"] == id_loc:
                            if loc_rel["labels"][0] == "act:direction-of":
                                id_direction = loc_rel["from_id"]
                                for direction in result_little_red_hat:
                                    if direction["type"] == "labels" and direction["id"] == id_direction:
                                        action_bkg.loc.direction = story[0][direction["value"]["start"]:direction["value"]["end"]]


            # 查找发生时间
            for result_ele_x_occurs in result_little_red_hat:
                if result_ele_x_occurs["type"] == "number" and result_ele_x_occurs["from_name"] == "x-occurs":
                    if result_ele_x_occurs["id"] == id_action:
                        my_action.x_occurs = result_ele_x_occurs["value"]["number"]
                        break
            
            # 处理 bkg 和 loc 参数
            if len(action_bkgs) == 0:
                key_action_list.append(my_action)
            else:
                for idx, action_bkg in enumerate(action_bkgs):
                    my_bkg_name = action_bkg.name
                    my_loc_name = None
                    my_direction = None
                    if action_bkg.loc is not None:
                        my_loc_name = action_bkg.loc.name
                        my_direction = action_bkg.loc.direction
                    my_occur = my_action.x_occurs + 0.001 * idx # 不同背景的两个动作先后发生，但也不能晚于下一个动作的发生
                    my_final_action = MyAction(my_action.my_type, my_action.trigger, my_action.subject, my_action.object, my_action.indirect_object, my_bkg_name, my_loc_name, my_action.constraint, my_direction, my_action.original_name, my_action.another_name, my_occur)

                    # 添加到关键动作列表
                    key_action_list.append(my_final_action)

    # 动作按照发生时间排序
    key_action_list.sort(key=lambda x: x.x_occurs)


    # 初始化动作文件
    clear_file("../out/actions.txt")

    # 写入文件
    for idx_action, my_key_action in enumerate(key_action_list):
        add_to_file("../out/actions.txt", f"动作 {idx_action}：{my_key_action.trigger}\n")
        # 输出动作的参数，格式：\t 参数
        add_to_file("../out/actions.txt", f"\t类型：{my_key_action.my_type}\n")
        add_to_file("../out/actions.txt", f"\t主语：{my_key_action.subject}\n")
        add_to_file("../out/actions.txt", f"\t宾语：{my_key_action.object}\n")
        add_to_file("../out/actions.txt", f"\t间接宾语：{my_key_action.indirect_object}\n")
        add_to_file("../out/actions.txt", f"\t背景：{my_key_action.background}\n")
        add_to_file("../out/actions.txt", f"\t地点：{my_key_action.location}\n")
        add_to_file("../out/actions.txt", f"\t约束：{my_key_action.constraint}\n")
        add_to_file("../out/actions.txt", f"\t方位：{my_key_action.direction}\n")
        add_to_file("../out/actions.txt", f"\t原名：{my_key_action.original_name}\n")
        add_to_file("../out/actions.txt", f"\t代称：{my_key_action.another_name}\n")
        add_to_file("../out/actions.txt", f"\t发生时间：{my_key_action.x_occurs}\n")

if __name__ == '__main__':
    
    # 读数据
    json_label_data = read_from_json('../project-5-at-2024-12-01-23-31-6187a354.json')
    print(f"读取了 {len(json_label_data)} 行标注数据")
    txt_story = read_from_file('../story/xiaohongmao.txt')
    print(f"读取了 {len(txt_story)} 行故事，共 {len(''.join(txt_story))} 个字符")
    list_action_label = read_from_json('../config/action_label.json')
    print(f"读取了 {len(list_action_label)} 个动作标签")

    # 验证
    validate_little_red_hat(json_label_data, txt_story, list_action_label)